package org.micode.demo.biz.service.impl;

import org.micode.common.helper.I18nMsgHelper;
import org.micode.common.helper.PasswordHelper;
import org.micode.demo.biz.service.BizSysConfigService;
import org.micode.demo.biz.service.BizSysUserService;
import org.micode.common.exception.DataException;
import org.micode.common.exception.VerifyFailException;
import org.micode.common.helper.MethodHelper;
import org.micode.demo.db.domain.dto.SysUserExtDTO;
import org.micode.demo.db.enums.DisableFlagEnum;
import org.micode.demo.db.enums.UserTypeEnum;
import org.micode.demo.db.service.DaoSysUserExtService;
import org.micode.libs.dao.helper.UserHelper;
import org.micode.demo.biz.vo.SysUserVO;
import org.micode.demo.db.cache.user.SysUserCache;
import org.micode.demo.db.domain.dto.SysUserDTO;
import org.micode.demo.db.service.DaoSysMenuService;
import org.micode.demo.db.service.DaoSysUserService;
import org.micode.demo.db.vo.ChangePwdVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import sun.nio.cs.ext.IBM833;

import java.util.Objects;
import java.util.Set;

/**
 * 用户服务，登录、保存个人信息等
 */
@Service
@Slf4j
public class BizSysUserServiceImpl implements BizSysUserService {

    private static final String DEFAULT_PWD = "User123456";

    @Value("${security.key:micode001}")
    private String securityKey;

    @Value("${security.iv:micode2021}")
    private String securityIv;

    @Autowired
    private DaoSysUserService daoSysUserService;

    @Autowired
    private DaoSysMenuService daoSysMenuService;

    @Autowired
    private DaoSysUserExtService daoSysUserExtService;

    @Autowired
    private BizSysConfigService bizSysConfigService;

    @Override
    public Boolean userLogout(SysUserCache userCache) {
        return Boolean.TRUE;
    }

    @Override
    public Integer updateUserPassword(ChangePwdVO pwdVO) {
        // 检查当前密码是否正确
        SysUserDTO user = MethodHelper.invoke(daoSysUserService::get, pwdVO.getUserId());
        if (null != user) {
            String pwd = user.getPassword();
            String currentPwd = PasswordHelper.decryptBase64AES(pwdVO.getCurrentPassword(), securityKey, securityIv);
            String cipherPwd = getCipherPassword(currentPwd, user.getSalt());
            if (!cipherPwd.equals(pwd)) {
                throw new DataException(I18nMsgHelper.get("valid.user.incorrect.currentPassword"));
            }

            String newPassword = PasswordHelper.decryptBase64AES(pwdVO.getNewPassword(), securityKey, securityIv);

            return innerUpdatePassword(pwdVO.getUserId(), newPassword,
                    pwdVO.getModifiedUserId(), pwdVO.getLoginApp(), pwdVO.getLoginIp());

        }
        return null;
    }

    @Override
    public Integer resetPassword(SysUserDTO sysUser) {
        SysUserDTO user = MethodHelper.invoke(daoSysUserService::get, sysUser.getUserId());
        if (null != user) {
            // 更新密码
            String thePwd = bizSysConfigService.defaultUserPassword();
            if (user.getUserType().equals(UserTypeEnum.ADMIN.getValue())) {
                thePwd = bizSysConfigService.defaultAdminPassword();
            }
            // 更新密码
            return innerUpdatePassword(sysUser.getUserId(), thePwd,
                    sysUser.getUpdUser(), sysUser.getUpdProg(), sysUser.getUpdIp());
        }
        return null;
    }

    private Integer innerUpdatePassword(Long userId, String thePwd,
                                        Long updUser, String updProg, String updIp) {
        String salt = UserHelper.getNewSalt();
        String newPwd = getCipherPassword(thePwd, salt);

        SysUserDTO updateObj = new SysUserDTO();

        updateObj.setUserId(userId);
        updateObj.setPassword(newPwd);
        updateObj.setSalt(salt);

        updateObj.setUpdUser(updUser);
        updateObj.setUpdProg(updProg);
        updateObj.setUpdIp(updIp);

        return MethodHelper.invoke(daoSysUserService::updateUserPassword, updateObj);
    }

    @Override
    public SysUserDTO insert(SysUserDTO userDTO) {
        userDTO.setSalt(UserHelper.getNewSalt());
        String newPwd = getCipherPassword(bizSysConfigService.defaultUserPassword(), userDTO.getSalt());
        userDTO.setPassword(newPwd);
        return MethodHelper.invoke(daoSysUserService::insert, userDTO);
    }

    @Override
    public SysUserDTO loginForTest(SysUserVO userVO) {
        if (null == userVO || null == userVO.getUserId()) {
            throw new DataException(I18nMsgHelper.get("valid.user.need-specified.userId"));
        }

        return MethodHelper.invoke(daoSysUserService::get, userVO.getUserId());
    }

    @Override
    public SysUserDTO loginByAccount(SysUserVO userVO) {
        try {
            SysUserDTO ret = this.innerLoginForAccount(userVO);
            //判断登录次数
            SysUserExtDTO userExtDTO = daoSysUserExtService.getOne(new SysUserExtDTO() {{
                setUserId(ret.getUserId());
            }});
            if (!Objects.isNull(userExtDTO)) {
                int loginNum = bizSysConfigService.loginNumWhenLockUser();
                if (userExtDTO.getLoginNum() > loginNum) {
                    log.error(I18nMsgHelper.get("fail.user.too-many.login-times") + " : " + loginNum);
                    throw new DataException(I18nMsgHelper.get("fail.user.too-many.login-times") + " : " + loginNum);
                }
            }

            // 登录成功，把登录次数清0
            clearLoginNum(ret);
            return ret;
        } catch (Exception e) {
            log.error(I18nMsgHelper.get("fail.BizSysUserServiceImpl-loginByAccount.call"), e);
            incLoginNum(userVO);//更新登录错误次数
            throw new DataException(e.getMessage());
        }
    }

    private void clearLoginNum(SysUserDTO ret) {
        try {
            SysUserExtDTO extDTO = daoSysUserExtService.get(ret.getUserId());
            if (null != extDTO) {
                SysUserExtDTO updateDTO = new SysUserExtDTO();
                updateDTO.setUserId(extDTO.getUserId());
                updateDTO.setLoginNum(0L);
                daoSysUserExtService.update(updateDTO);
            }
        } catch (Exception e) {
            log.warn(I18nMsgHelper.get("fail.BizSysUserServiceImpl-clearLoginNum.call"), e);
        }
    }

    private void incLoginNum(SysUserVO userVO) {
        try {
            boolean locked = false;
            SysUserExtDTO extDTO = daoSysUserExtService.getByLoginName(userVO.getLoginName());
            if (null != extDTO) {
                SysUserExtDTO updateDTO = new SysUserExtDTO();
                updateDTO.setUserId(extDTO.getUserId());
                updateDTO.setLoginNum(extDTO.getLoginNum() + 1);
                daoSysUserExtService.update(updateDTO);
                if (bizSysConfigService.loginNumWhenLockUser() <= updateDTO.getLoginNum()) {
                    // 锁定账号(禁用)
                    SysUserDTO sysUserDTO = new SysUserDTO();
                    sysUserDTO.setUserId(extDTO.getUserId());
                    sysUserDTO.setDisableFlag(DisableFlagEnum.YES.getValue());
                    daoSysUserService.update(sysUserDTO);
                }
            }
        } catch (Exception e) {
            log.warn(I18nMsgHelper.get("fail.BizSysUserServiceImpl-incLoginNum.call"), e);
        }
    }

    private String getCipherPassword(String password, String salt) {
        return UserHelper.getCipherPassword(password, salt);
    }

    private SysUserDTO getUserByLoginName(String loginName) {
        if (StringUtils.isEmpty(loginName)) {
            return null;
        }

        SysUserDTO example = new SysUserDTO();
        example.setLoginName(loginName);

        return MethodHelper.invoke(daoSysUserService::getOne, example);
    }

    private SysUserDTO innerLoginForAccount(SysUserVO userVO) {
        if (StringUtils.isBlank(userVO.getLoginPassword())) {
            log.error(I18nMsgHelper.get("valid.user.password.not-null"));
            throw new VerifyFailException(I18nMsgHelper.get("valid.user.password.not-null"));
        }

        SysUserDTO userExist = getUserByLoginName(userVO.getLoginName());
        if (null == userExist) {
            log.error(I18nMsgHelper.get("valid.user.account.not-found"));
            throw new VerifyFailException(I18nMsgHelper.get("valid.user.account.not-found"));
        }
        if (DisableFlagEnum.YES.getValue() == userExist.getDisableFlag()) {
            log.error(I18nMsgHelper.get("valid.user.account.disabled"));
            throw new VerifyFailException(I18nMsgHelper.get("valid.user.account.disabled"));
        }

        // 先对前端过来的加密密码进行解密
        String pwd = decryptPassword(userVO.getLoginPassword());
        // String pwd = userVO.getLoginPassword();
        String md5pwd = getCipherPassword(pwd, userExist.getSalt());
        if (!md5pwd.equals(userExist.getPassword())) {
            log.error(I18nMsgHelper.get("valid.user.password.incorrect") + ", " + md5pwd);
            throw new VerifyFailException(I18nMsgHelper.get("valid.user.password.incorrect"));
        }

        return userExist;
    }

    @Override
    public Set<String> getUserPermissions(Long userId) {
        return daoSysMenuService.listPerms(userId);
    }

    @Override
    public String decryptPassword(String pwd) {
        return PasswordHelper.decryptBase64AES(pwd, securityKey, securityIv);
    }

}
